`timescale 1ns / 1ps
module Race_controller(
    input        clk,
    input        jump,
    input        if_stall,
    input        mem_stall,
    input        predict_jump_exe,
    input        switch_mode,

    output       PC_stall,
    output       IFID_stall,
    output       IDEXE_stall,
    output       EXEMEM_stall,
    output       MEMWB_stall,
    output       IFID_flush,
    output       IDEXE_flush,
    output       EXEMEM_flush,
    output       MEMWB_flush
);

// wire predict_wrong = (~jump && predict_jump_exe);  // 预测不跳实际跳转
// wire predict_wrong2 = (jump && ~predict_jump_exe); // 预测跳转实际不跳
// // wire predict_wrong_pack = (lock==2'b11);
// assign PC_stall = mem_stall | if_stall | lock;                                         // 只要是在读写 RAM， PC都要 stall
// assign IFID_stall = mem_stall | lock;
// assign IDEXE_stall = (jump & ~predict_jump_exe) & if_stall | mem_stall;                 // 跳转且正在取指的时候，需要防止指令进入 EXE 直接执行 
// assign EXEMEM_stall = mem_stall;                                                        // 正在读写内存数据时，EXEMEM stall 以保持 MEM阶段的指令
// assign MEMWB_stall = 1'b0;                                                              // 读写内存的时候 MEM_mem 保持上一拍的东西，flush 一下就好

//                                                                                         // stall 的目的包括保持下一拍的指令，因此 stall 的时候不能 flush
// assign IFID_flush =  ~IFID_stall & (if_stall )  ;       // if stall 的时候，PC保持，已经吐出的指令逐级走过流水线，空的部分就补 bump ; jump 是在控制冲突刷新用
// assign IDEXE_flush = ~IDEXE_stall & (predict_wrong | predict_wrong2);                         // 控制冲突刷新 IFID 和 IDEXE
// assign EXEMEM_flush = ~EXEMEM_stall & ((jump & ~predict_jump_exe) & if_stall);          // 跳转且正在取指的时候，将 EXEMEM flush, 不往后传指令
// assign MEMWB_flush = mem_stall;                                                         // 读写内存的时候 MEM_mem 保持上一拍的东西，将 WB flush 一下就好

reg lock;
always@(posedge clk)begin
    if(~lock && jump) lock <= 1;
    else if (lock && ~if_stall) lock <= 0;
end

reg csrlock;
always@(posedge clk)begin
    if(~csrlock && switch_mode) csrlock <= 1;
    else if (csrlock && ~if_stall) csrlock <= 0;
end

assign PC_stall = mem_stall | if_stall | lock;                          // 只要是在读写 RAM， PC都要 stall
assign IFID_stall = mem_stall;
assign IDEXE_stall = jump & if_stall | mem_stall;                       // 跳转且正在取指的时候，需要防止指令进入 EXE 直接执行 
assign EXEMEM_stall = mem_stall;                                        // 正在读写内存数据时，EXEMEM stall 以保持 MEM阶段的指令
assign MEMWB_stall = 0;                                                 // 读写内存的时候 MEM_mem 保持上一拍的东西，flush 一下就好

                                                                        // stall 的目的包括保持下一拍的指令，因此 stall 的时候不能 flush
assign IFID_flush =  ~IFID_stall & (if_stall | jump | lock) | switch_mode;            // if stall 的时候，PC保持，已经吐出的指令逐级走过流水线，空的部分就补 bump ; jump 是在控制冲突刷新用
assign IDEXE_flush = ~IDEXE_stall & jump | switch_mode;                       // 控制冲突刷新 IFID 和 IDEXE
assign EXEMEM_flush = ~EXEMEM_stall & (jump  & if_stall) | switch_mode;       // 跳转且正在取指的时候，将 EXEMEM flush, 不往后传指令
assign MEMWB_flush = mem_stall | switch_mode;                                // 读写内存的时候 MEM_mem 保持上一拍的东西，将 WB flush 一下就好

endmodule